 #include "ModulsManager\CPU_drv_I2C.h"
 #include "inithard.h"
 #include "board.h"





uint8_t bufI2C0[BufI2C0size], *pbufI2C0, NbyteI2C0;
STATUS_I2C STAT_I2C0;
xSemaphoreHandle xSemI2C0fnsh;
xSemaphoreHandle xMtxI2C0;


extern void RegisterIrq (int irq, unsigned int isr,int pri);

__irq __arm void I2C0_Handler(void);
void formCOMrd(uint8_t id, uint16_t adr, uint8_t nBytes);
void formCOMwr(uint8_t id, uint16_t adr, uint8_t nBytes);
void formCOM(uint8_t id, uint16_t adr, uint8_t nBytes);
void formDATrd(uint8_t id);
void formDATwr(uint8_t id, uint8_t nB, uint8_t const *pS);
void sendI2C0(uint8_t nbytes);
uint8_t CRC8_CITT(uint8_t *pcBlock, uint8_t len);


void I2C0_Init(void){
//	uint32_t fcclk;
//Create Semaphores
  vSemaphoreCreateBinary(xMtxI2C0);
  vSemaphoreCreateBinary(xSemI2C0fnsh); xSemaphoreTake(xSemI2C0fnsh,portMAX_DELAY);
//I2C0 Interrupt Set Up
  RegisterIrq(VIC_I2C0,(uint32_t)I2C0_Handler,0);
//
  pbufI2C0 = bufI2C0;  NbyteI2C0 = 0;
}



void I2C0_Init_After_PowerUp(void)
{ 
//Pins P0.27 & P0.28 switch to SDA & SCL  
  PINSEL1_bit.P0_27  = PINSEL1_bit.P0_28  = 1;//First alternate function
  PINMODE1_bit.P0_27 = PINMODE1_bit.P0_28 = 2;//Pin has neither pull-up nor pull-down resistor
  FIO0DIR_bit.P0_27  = FIO0DIR_bit.P0_28  = 1;//Outputs
  FIO0MASK_bit.P0_27 = FIO0MASK_bit.P0_28 = 0;//
//Enable Clock Frequency for I2C0
  PCLKSEL0_bit.PCLK_I2C0 = 0;//Fpclk_I2C0 = Fcclk/4
  PCONP_bit.PCI2C0 = 1;
//Set Up Bit Frequency of I2C0 
  I2C0SCLH = I2C0SCLHdef;  I2C0SCLL = I2C0SCLLdef;  
//Turn ON I2C0
  I2C0en;
//INterrupt
  VICINTENABLE_bit.I2C0 = 1;
}





__irq __arm void I2C0_Handler(void)
{ 
  uint32_t StopOn = 0;
  portBASE_TYPE xHiPriTaskW = pdFALSE;
//
  AA0on;
//
  switch(I2C0STAT)
   {
     case(AlNoADR) : STA0on; NbyteI2C0 = 0; STAT_I2C0 = ARB_LOST; 
                  break;
     case(mDATrNA) : *pbufI2C0++ = I2C0DAT; StopOn = 1;
                  break;
     case(mSLAwNA) :
     case(mSLArNA) : STAT_I2C0 = NO_SLAVE; StopOn = 1;
                  break;
     case(mDATwNA) : STAT_I2C0 = CRC_ERROR;   StopOn = 1;
                  break;
     case(mSTART)  :
     case(mReSTART): STA0off; pbufI2C0 = &bufI2C0[0];
     case(mSLAwA)  :
     case(mDATwA)  : if(!NbyteI2C0) {StopOn = 1;} else {I2C0DAT = *pbufI2C0++; --NbyteI2C0;};
                  break;
     case(mDATrA)  : *pbufI2C0++ = I2C0DAT;
     case(mSLArA)  : if(NbyteI2C0>1) {--NbyteI2C0;} else {AA0off;}
                  break;
     case(BusERR)  : 
          default  : STAT_I2C0 = BUS_ERROR;   StopOn = 1;
    }
//
  if(StopOn)
   { 
     STO0on;       xSemaphoreGiveFromISR(xSemI2C0fnsh,&xHiPriTaskW);
   }
  SI0clr;
  VICADDRESS = 0;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/






STATUS_I2C WriteToModul(uint8_t devID, uint16_t adr, uint8_t Nbytes, uint8_t const *pSource)
{
  if(Nbytes>BufI2C0size-2) return BUF_OVERFLOW;
  if( xSemaphoreTake(xMtxI2C0,TimeOutI2Cgrab)==pdPASS )
    {
      STAT_I2C0 = NO_ERROR;
      formCOMwr(devID,adr,Nbytes);   sendI2C0(COMlen);
      if(STAT_I2C0==NO_ERROR) 
        { formDATwr(devID,Nbytes,pSource);  sendI2C0(Nbytes+2); }
      xSemaphoreGive(xMtxI2C0);
      return STAT_I2C0;
     }
   else { return I2C_BUSY; }
}


STATUS_I2C ReadFromModul(uint8_t devID, uint16_t adr, uint8_t Nbytes)
{
  if(Nbytes>BufI2C0size-2) return BUF_OVERFLOW;
  if( xSemaphoreTake(xMtxI2C0,TimeOutI2Cgrab)==pdPASS )
    {
      STAT_I2C0 = NO_ERROR;
      formCOMrd(devID,adr,Nbytes);   sendI2C0(COMlen);
      if(STAT_I2C0==NO_ERROR)
       {
         formDATrd(devID);  sendI2C0(Nbytes+2);
         if(STAT_I2C0==NO_ERROR && CRC8_CITT(&bufI2C0[0],Nbytes+2)) STAT_I2C0 = CRC_ERROR;
        }
      xSemaphoreGive(xMtxI2C0);
      return STAT_I2C0;
     }
   else { return I2C_BUSY; }
}



uint8_t BufToCHAR(uint8_t Cell)
{ if( (++Cell) > BufI2C0size-1 ) {return 0;} else {return bufI2C0[Cell];} }


uint16_t BufToUSHT(uint8_t Cell)
{
  if( (++Cell) > BufI2C0size-3 )
    { return 0; }
   else
    { return ((uint16_t)bufI2C0[Cell+1]<<8)+bufI2C0[Cell]; }
}

uint32_t BufToUINT(uint8_t Cell)
{ 
  if( (++Cell) > BufI2C0size-5 )
    { return 0; }
   else
    {
      return ((uint32_t)bufI2C0[Cell+3]<<24)+((uint32_t)bufI2C0[Cell+2]<<16)+((uint32_t)bufI2C0[Cell+1]<<8)+bufI2C0[Cell];
    }
}



bool SDA_SCL_Stretch_Check(void)
{
  uint32_t  n_of_try;
  
  for( n_of_try=10; n_of_try; --n_of_try )
   {
     if(FIO0PIN_bit.P0_27 && FIO0PIN_bit.P0_28) return true;
     vTaskDelay(1);
   }
  return false;
}

void formCOMrd(uint8_t id, uint16_t adr, uint8_t nBytes)
{
  formCOM(id, adr&0x7FFF, nBytes);
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
void formCOMwr(uint8_t id, uint16_t adr, uint8_t nBytes)
{
  formCOM(id, adr|0x8000, nBytes);
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
void formCOM(uint8_t id, uint16_t adr, uint8_t nBytes)
{
  bufI2C0[0] = (id<<2) | COMbit;
  bufI2C0[1] = (uint8_t)adr;  bufI2C0[2] = adr>>8;  bufI2C0[3] = nBytes;
  bufI2C0[4] = CRC8_CITT(&bufI2C0[0],4);
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

void formDATrd(uint8_t id)   { bufI2C0[0] = (id<<2) | RDbit; }
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

void formDATwr(uint8_t id, uint8_t nB, uint8_t const *pS)
{ uint32_t cell=1;
  bufI2C0[0] = (id<<2) | WRbit;
  while(cell<=nB) { bufI2C0[cell++] = *pS++; }
  bufI2C0[cell] = CRC8_CITT(&bufI2C0[0],cell);
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/




void sendI2C0(uint8_t nbytes)
{
  NbyteI2C0 = nbytes>BufI2C0size ? BufI2C0size : nbytes;
//
  if( SDA_SCL_Stretch_Check() )
    {
      pbufI2C0 = bufI2C0;
      STA0on;
      if( xSemaphoreTake(xSemI2C0fnsh,TimeOutI2Cfnsh) == pdFALSE )
        { I2C0dis;   I2C0en;    STAT_I2C0 = TIME_OUT; }
    }
   else { STAT_I2C0 = I2C_STRETCH; }
     
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

uint8_t CRC8_CITT(uint8_t *pcBlock, uint8_t len)
{ uint8_t crc = 0x00, i;
 
  while(len--)
   {
     crc ^= *pcBlock++;
     for(i=0; i<8; i++)  crc = crc&0x80 ? (crc<<1)^0x07 : crc<<1;
    }
  return crc;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

